﻿using Microsoft.EntityFrameworkCore;
using Project.Core.Config.Config.DbConnect;
using Project.Core.Config.Entity;
using Project.Core.Config.Entity.Dto;

namespace Project.Core.Config.Mapper.Impl {
    public class BaseMapperImpl<T, L> : BaseMapper<T, L> where T : BaseEntity<L> {
        public readonly AppDbContext Context;
        public DbSet<T> DbSet;

        public BaseMapperImpl(AppDbContext context) {
            this.Context = context;
            this.DbSet = context.Set<T>();
        }

        public IQueryable<T> GetAll() {
            return DbSet;
        }

        public async Task<List<T>> GetAllAsync() {
            return await DbSet.ToListAsync();
        }

        public Page GetAll(Page p) {
            return Page(p);
        }

        public T GetById(L id) {
            return DbSet.Find(id);
        }

        public async Task<T> GetByIdAsync(L id) {
            return await DbSet.FindAsync(id);
        }

        public IEnumerable<T> GetByIds(IEnumerable<L> idList) {
            //var ids = string.Join(",", idList);
            //防SQL注入正确代码
            //MySqlParameter[] sqlparment = new MySqlParameter[] { new MySqlParameter("@ids", ids) };
            //List<T> list = dbSet.FromSqlRaw(@$"SELECT * FROM sys_menu WHERE FIND_IN_SET(id,@ids);", sqlparment).ToList();

            List<T> list = DbSet.Where<T>(p => idList.Contains(p.Id)).ToList();
            return list;
        }

        public async Task<List<T>> GetByIdsAsync(IEnumerable<L> idList) {
            List<T> list = await DbSet.Where<T>(p => idList.Contains(p.Id)).ToListAsync();
            return list;
        }

        public T Add(T data) {
            DbSet.Add(data);
            Context.SaveChanges();
            return data;
        }

        public async Task<T> AddAsync(T data) {
            await DbSet.AddAsync(data);
            await Context.SaveChangesAsync();
            return data;
        }

        public IEnumerable<T> AddBatch(IEnumerable<T> dataList) {
            DbSet.AddRange(dataList);
            Context.SaveChanges();
            return dataList;
        }

        public async Task<List<T>> AddBatchAsync(IEnumerable<T> dataList) {
            await DbSet.AddRangeAsync(dataList);
            await Context.SaveChangesAsync();
            return dataList.ToList();
        }

        public T Delete(T data) {
            var d = DbSet.Remove(data);//返回一个实体的跟踪状态和元数据
            Context.SaveChanges();
            return d.Entity;//转换为实体本身
        }

        public async Task<T> DeleteAsync(T data) {
            var d = DbSet.Remove(data);
            await Context.SaveChangesAsync();
            return d.Entity;
        }

        public T DeleteById(L id) {
            T data = DbSet.Find(id);
            if (data != null) {
                DbSet.Remove(data);
                Context.SaveChanges();
            }
            return data;
        }

        public async Task<T> DeleteByIdAsync(L id) {
            T data = await DbSet.FindAsync(id);
            if (data != null) {
                DbSet.Remove(data);
                await Context.SaveChangesAsync();
            }
            return data;
        }

        public IEnumerable<T> DeleteBatch(IEnumerable<T> dataList) {
            DbSet.RemoveRange(dataList);
            Context.SaveChanges();
            return dataList;
        }

        public async Task<List<T>> DeleteBatchAsync(IEnumerable<T> dataList) {
            DbSet.RemoveRange(dataList);
            await Context.SaveChangesAsync();
            return dataList.ToList();
        }

        public IEnumerable<T> DeleteBatchIds(IEnumerable<L> idList) {
            var dataList = GetByIds(idList);
            DbSet.RemoveRange(dataList);
            Context.SaveChanges();
            return dataList;
        }

        public async Task<List<T>> DeleteBatchIdsAsync(IEnumerable<L> idList) {
            var dataList = await GetByIdsAsync(idList);
            DbSet.RemoveRange(dataList);
            await Context.SaveChangesAsync();
            return dataList.ToList();
        }

        public T Update(T updateData) {
            var data = DbSet.Attach(updateData);
            data.State = Microsoft.EntityFrameworkCore.EntityState.Modified;
            Context.SaveChanges();
            return updateData;
        }

        public async Task<T> UpdateAsync(T updateData) {
            var data = DbSet.Update(updateData);
            await Context.SaveChangesAsync();
            return data.Entity;
        }

        public IEnumerable<T> UpdateBatch(IEnumerable<T> updateData) {
            //dbSet.AttachRange(updateData);
            //foreach (var data in updateData) {
            //    context.Entry(data).State = EntityState.Modified;
            //}
            DbSet.UpdateRange(updateData);
            Context.SaveChanges();
            return updateData;
        }
        public async Task<List<T>> UpdateBatchAsync(IEnumerable<T> updateData) {
            DbSet.UpdateRange(updateData);
            await Context.SaveChangesAsync();
            return updateData.ToList();
        }

        public Page<T> Page(Page page) {
            var offset = (page.Current - 1) * page.Size;
            var totalItems = DbSet.Count();
            if (offset >= totalItems) {
                offset = ((int)Math.Ceiling((double)DbSet.Count() / page.Size) - 1) * page.Size;
            }
            //IEnumerable<T> ls = dbSet.Skip(offset).Take(page.size).ToArray();
            IEnumerable<T> ls = (from row in (DbSet.AsEnumerable().Select((item, index) => new { item, RowNum = index }))
                                 where row.RowNum >= offset && row.RowNum < offset + page.Size
                                 select row.item).ToList();

            var entityPage = new Page<T>(page.Current, page.Size);
            entityPage.Records = ls;
            entityPage.TotalItems = totalItems;
            return entityPage;
        }

        public Page<E> Page<E>(Page page, IEnumerable<E> list) {
            int offset = (page.Current - 1) * page.Size;    //为分页偏移量
            var totalItems = list.Count();
            if (offset >= list.Count()) {
                offset = ((int)Math.Ceiling((double)list.Count() / page.Size) - 1) * page.Size;
            }
            //IEnumerable<E> ls = list.Skip(offset).Take(page.size).ToList();
            IEnumerable<E> ls = (from row in (list.Select((item, index) => new { item, RowNum = index }))
                                 where row.RowNum >= offset && row.RowNum < offset + page.Size
                                 select row.item).ToList();

            var entityPage = new Page<E>(page.Current,page.Size);
            entityPage.Records = ls;
            entityPage.TotalItems = totalItems;
            return entityPage;
        }

    }
}
